
class Token {
    // 注册几个Token类型
    static INVALID_TOKEN_TYPE =  0;
    static PLUS = 1;
    static MULT = 2;
    static DOT = 3;
    static INT = 4;
    static VEC = 5
    static ID = 6;
    static ASSIGN = 7;
    static PRINT = 8;
    static STAT_LIST = 9; 
    type : number;
    text:string 

    constructor(type:number,text:string = ""){
        this.type = type;
        this.text = text;
    }

    toString(){
        return this.text
    }
}
/**
 * AST抽象类
 */
class HeteroAST {
    token:Token | null;
    constructor(t:Token | null = null){
        this.token = t;
    }
    toString(){
        return this.token ? this.token.toString() : "<null>"
    }
    toStringTree(){
        return this.toString();
    }
}

abstract class VecMathNode extends HeteroAST{
    constructor(token:Token | null){
        super(token)
    }
    abstract visit(visitor:VecMathVisitor):void;
}
/**
 * 具体实现语法节点
 */
class ExprNode extends VecMathNode{
    constructor(t:Token | null = null){
        super(t)
    }
    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}

class StatNode extends VecMathNode{
    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}

class StatListNode extends VecMathNode {
    elements:StatNode[] = [];
    constructor(elements:StatNode[]){
        super(new Token(Token.STAT_LIST));
        this.elements = elements
    }
    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}
class IntNode extends ExprNode {
    constructor(t:Token){
        super(t)
    }
    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}

class VarNode extends ExprNode {
    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}


class AddNode extends ExprNode{
    left:ExprNode;
    right:ExprNode;

    constructor(left:ExprNode,addToken:Token,right:ExprNode){
        super(addToken);
        this.left = left;
        this.right = right;
    }
    
    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}
class MultNode extends ExprNode {
    left:ExprNode;
    right:ExprNode;

    constructor(left:ExprNode,addToken:Token,right:ExprNode){
        super(addToken);
        this.left = left;
        this.right = right;
    }
    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}
class DotProductNode extends ExprNode {
    left:ExprNode;
    right:ExprNode;

    constructor(left:ExprNode,addToken:Token,right:ExprNode){
        super(addToken);
        this.left = left;
        this.right = right;
    }

    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}

class VectorNode extends ExprNode {
    elements:ExprNode[] = [];

    constructor(t:Token | null,elements:ExprNode[]){
        super(t);
        this.elements = elements;
    }

    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}

class ListNode extends ExprNode {
    elements:ExprNode[] = [];

    constructor(elements:ExprNode[]){
        super(null);
        this.elements = elements;
    }

    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}

class AssignNode extends StatNode {
    id:VarNode;
    value:ExprNode;

    constructor(id:VarNode,token:Token | null,value:ExprNode){
        super(token)
        this.id = id;
        this.value  = value;
    }

    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}

class PrintNode extends StatNode {
    value:ExprNode;

    constructor(token:Token | null,value:ExprNode){
        super(token)
        this.value = value;
    }

    visit(visitor:VecMathVisitor){
        visitor.visit(this);
    }
}

// 访问器
interface VecMathVisitor {
   visit(n:AssignNode):void;
   visit(n:PrintNode):void;
   visit(n:StatListNode):void;
   visit(n:VarNode):void;
   visit(n:AddNode):void;
   visit(n:DotProductNode):void;
   visit(n:IntNode):void;
   visit(n:MultNode):void;
   visit(n:VectorNode):void;
}

class PrintVisitor implements VecMathVisitor{
    visit(n: AssignNode): void;
    visit(n: PrintNode): void;
    visit(n: StatListNode): void;
    visit(n: VarNode): void;
    visit(n: AddNode): void;
    visit(n: DotProductNode): void;
    visit(n: IntNode): void;
    visit(n: MultNode): void;
    visit(n: VectorNode): void;
    visit(n: any): void {
        if( n instanceof AssignNode){
            n.id.visit(this);
            process.stdout.write("=");
            n.value.visit(this);
            process.stdout.write("\n");
        }else if(n instanceof StatListNode){
            n.elements.forEach(e => e.visit(this))
        }else if(n instanceof PrintNode){
            process.stdout.write("print ");
            n.value.visit(this);
            process.stdout.write("\n");
        }else if(n instanceof AddNode){
            n.left.visit(this);
            process.stdout.write("+")
            n.right.visit(this);
        }else if(n instanceof DotProductNode){
            n.left.visit(this);
            process.stdout.write(".")
            n.right.visit(this);
        }else if(n instanceof MultNode){
            n.left.visit(this);
            process.stdout.write("*")
            n.right.visit(this);
        }else if(n instanceof IntNode){
            process.stdout.write(n.toString());
        }else if(n instanceof VarNode){
            process.stdout.write(n.toString())
        }else if(n instanceof VectorNode){
            process.stdout.write("[");
            n.elements.forEach((e,i)=>{
                if(i>0){
                    process.stdout.write(", ")
                }
                e.visit(this)
            })
            process.stdout.write(']');
        }
    }

}


export {
    Token,
    AddNode,
    VectorNode,
    IntNode,
    StatNode,
    VarNode,
    AssignNode,
    ExprNode,
    MultNode,
    PrintNode,
    StatListNode,
    PrintVisitor
}